package functionTypes;

import Abstracts.AbstractGeneticFunction;
import Abstracts.AbstractSinglePropertyFunction;

public class OldFunction implements AbstractGeneticFunction,Cloneable{

	public AbstractSinglePropertyFunction[] subfunctions; 
	
	public OldFunction(){
		generateFunction();
	}
	
	public OldFunction clone() throws CloneNotSupportedException{
		OldFunction obj=(OldFunction)super.clone();
		obj.subfunctions = new AbstractSinglePropertyFunction[subfunctions.length];		
		for (int i=0;i!=subfunctions.length;++i){
			obj.subfunctions[i] = subfunctions[i].clone();
		}
		return obj;
	}
	
	/*
	public void clone(AbstractFunction f){
		f = new OldFunction();
		AbstractSinglePropertyFunction[] subs = new AbstractSinglePropertyFunction[this.subfunctions.length];
		for (int i=0;i!=subs.length;++i){
			subfunctions[i].clone(subs[i]);
		}
		f.createAbstractFunction(subs);
	}
	*/
	public double compute(double[] params) {
		double result = 0;
		
		for (AbstractSinglePropertyFunction f:subfunctions){
			double midResult=0;
			for (double d:params){
				midResult+=Math.pow(f.compute(d),2);
			}
			result+=1/(1+midResult);
		}
		
		result/=subfunctions.length;
		
		return result;
	}

	public void createAbstractFunction(AbstractSinglePropertyFunction[] args) {
		subfunctions = args;
	}
	
	
	public void mutate(double chance){
		for (AbstractSinglePropertyFunction f:subfunctions){
			if (Math.random()<chance){
				f.rebuild();
			}
		}
	}

	public void bigMutate(){
		for (AbstractSinglePropertyFunction f:subfunctions){
				f.rebuild();
		}
	}
	
	public OldFunction[] crossover(OldFunction f){
		OldFunction new1 = new OldFunction();
		OldFunction new2 = new OldFunction();
		
		int[] rand = new int[subfunctions.length+f.subfunctions.length];
		AbstractSinglePropertyFunction[] old = new AbstractSinglePropertyFunction[rand.length];
		
		int k = 0;
		for (;k<subfunctions.length;++k){
			old[k] = subfunctions[k];
		}
		
		for (int i=0;i<f.subfunctions.length;++i){
			old[k] = f.subfunctions[i];
			++k;
		}
		
		rand[0]=0;
		rand[1]=1;
		
		int count = 1;
		for (int i=2;i<rand.length;++i){
			rand[i]=(int)Math.round(Math.random());
			if (rand[i]==0){
				++count;
			}
		}
		
		AbstractSinglePropertyFunction[] new1functions = new AbstractSinglePropertyFunction[count];
		AbstractSinglePropertyFunction[] new2functions = new AbstractSinglePropertyFunction[rand.length-count];		
		
		int count1=0;
		int count2=0;
	
		for (int i=0;i<rand.length;++i){
			if (rand[i]==0){
				new1functions[count1]=old[i];
				++count1;
			}else{
				new2functions[count2]=old[i];
				++count2;
			}
		}
		
		new1.createAbstractFunction(new1functions);
		new2.createAbstractFunction(new2functions);
		return new OldFunction[]{this,f,new1,new2};
	}

	public void generateFunction() {
		subfunctions = new OldSinglePropertyFunction[(int)(Math.random()*5+5)];
		for (int i=0;i!=subfunctions.length;++i){
			subfunctions[i] = new OldSinglePropertyFunction();
		}
	}

	public AbstractSinglePropertyFunction[] getSubFunctions() {
		return subfunctions;
	}
	
}
